#ifndef AST_HPP
#define AST_HPP

#include <vector>
using namespace std;

class Token;

class Node {
public:
    virtual void dump();
};

enum OpType {
    AST_OP_ADD,
    AST_OP_SUB,
    AST_OP_MUL,
    AST_OP_DIV,
    AST_OP_MOD,
    AST_OP_BIT_AND,
    AST_OP_BIT_OR,
    AST_OP_BIT_XOR,
    AST_OP_LOG_AND,
    AST_OP_LOG_OR,
    AST_OP_LEFT_SHIFT,
    AST_OP_RIGHT_SHIFT,
    AST_OP_CMP,
};

class BinaryOp : public Node {
protected:
    OpType _op_type;
    Node* _left;
    Node* _right;
    
public:
    BinaryOp(OpType op_type, Node* left, Node* right) : 
        _op_type(op_type), _left(left), _right(right) {
    }

    void dump();

    void set_left(Node* left);
    void set_right(Node* right);
};

class ListNode : public Node {
private:
    vector<Node*>* _node_list;

public:
    ListNode();
    
    void add(Node* n);
    
    virtual void dump();
};

class CmpNode : public BinaryOp {
public:
    const static int CMP_LT = 0;
    const static int CMP_EQUAL = 1;

    int _cmp_op;

    CmpNode(int cmp_op) : BinaryOp(AST_OP_CMP, NULL, NULL), _cmp_op(cmp_op) {
    }

    CmpNode(Node* left, Node* right) : _cmp_op(-1), BinaryOp(AST_OP_CMP, left, right) {
    }

    virtual void dump();
};

class ConstInt : public Node {
public:
    int _value;
    
    ConstInt(int v) : _value(v) {}
    
    virtual void dump();
};

class ConstString : public Node {
public:
    char* _s;
};

class LogicNotNode: public Node {
private:
    Node* _value;
public:
    LogicNotNode(Node* v) : _value(v) {
    }

    Node* value() { return _value; }
    virtual void dump();
};

class VarNode : public Node {
private:
    char* _name;

public:
    VarNode(Token* name);
    
    virtual void dump();
};

class AssignNode : public Node {
private:
    VarNode* _left;
    Node*    _right;
    
public:
    AssignNode(VarNode* left, Node* right):
        _left(left), _right(right){}
        
    virtual void dump();
};

class PrintNode : public Node {
private:
    Node*    _value;
    
public:
    PrintNode(Node* value) : _value(value) {}
        
    virtual void dump();
};

class IfNode : public Node {
private:
    Node*   _cond;
    Node*   _then;
    Node*   _else;

public:
    IfNode(Node* cond, Node* then_part, Node* else_part) : 
        _cond(cond), _then(then_part), _else(else_part) {}

    virtual void dump();
};

#endif

